package lol.clann.minecraft.springboot.plugin.bukkit.impl;

import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.ruoshui.utils.java.exception.ExceptionUtils;
import com.ruoshui.utils.java.reflect.ReflectUtils;
import com.ruoshui.utils.java.reflect.model.FieldFilter;
import lol.clann.minecraft.springboot.SpringBootPlugin;
import lol.clann.minecraft.springboot.api.annotation.config.Configure;
import lol.clann.minecraft.springboot.api.bukkit.utils.LanguageUtils;
import lol.clann.minecraft.springboot.api.bukkit.utils.PluginUtils;
import lol.clann.minecraft.springboot.api.context.PluginContext;
import lol.clann.minecraft.springboot.api.context.SpringContext;
import lol.clann.minecraft.springboot.api.model.core.SBPConfig;
import lol.clann.minecraft.springboot.api.model.reflect.FieldInvoker;
import lol.clann.minecraft.springboot.bukkit.utils.NMSClasses;
import lombok.extern.slf4j.Slf4j;
import okio.BufferedSource;
import okio.Okio;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 这个bean启动时,会把服务端的语言替换成指定的语言
 * 语言文件优先级 plugins/SpringBootPlugin/lang > <language>.lang > en_us.lang
 *
 * @author pyz
 * @date 2019/6/15 4:57 PM
 */
@Slf4j
@Service
public class LanguageUtilsImpl_all implements LanguageUtils {
    private FieldInvoker instance;
    private FieldInvoker languageList;

    @Autowired
    private PluginUtils pluginUtils;
    private Map<String, String> languageMap;
    @Configure(value = "springbootplugin.server.language", comment = "服务端语言")
    private String language = "zh_cn";
    @Autowired
    private SBPConfig config;

    @PostConstruct
    private void init() throws Exception {
        instance = new FieldInvoker(ReflectUtils.getField(NMSClasses.getLocaleLanguage(), FieldFilter.create().setStatic(true).setType(NMSClasses.getLocaleLanguage())));
        languageList = new FieldInvoker(ReflectUtils.getField(NMSClasses.getLocaleLanguage(), FieldFilter.create().setStatic(false).setType(Map.class)));
        init0();
        LOGGER.info("语言映射已替换为:" + language);
    }

    @Override
    public String translateKey(String key) {
        return languageMap.getOrDefault(key, key);
    }

    private void init0() throws Exception {
        Object localeLanguage = instance.get(null);
        languageMap = (Map) languageList.get(localeLanguage);

        String langFileName = language + ".lang";

//        扫描classPath下所有语言文件
        LOGGER.info("开始扫描所有语言文件...");
        List<Resource> resources = SpringContext.findResources("classpath*:**/en_us.lang", "classpath*:**/" + language + ".lang");
        for (Resource resource : resources) {
            if (config.isDebugLanguage()) {
                LOGGER.info("注入语言文件:{}", resource.toString());
            }
            try (InputStream in = resource.getInputStream()) {
                Map<String, String> map = parseLangFile(in);
                languageMap.putAll(map);
            } catch (Throwable e) {
                List<String> msg = new ArrayList<>();
                while (e != null) {
                    msg.add(e.getClass().getSimpleName() + ":" + e.getMessage());
                    e = e.getCause();
                }
                LOGGER.warn("读取语言文件失败:" + resource.toString());
                for (String s : msg) {
                    LOGGER.warn(s);
                }
            }
        }

//      加载自定义语言映射
        File dir = new File(PluginContext.getPlugin(SpringBootPlugin.id).getDataFolder().toFile(), "lang");
        LOGGER.info("开始注册自定义语言文件:" + dir.getAbsolutePath());
        if (!dir.exists()) {
            dir.mkdirs();
            return;
        }
        List<File> customLangFiles = Files.walk(dir.toPath(), Integer.MAX_VALUE)
                .filter(p -> !Files.isDirectory(p))
                .map(p -> p.toFile())
                .filter(f -> f.getName().toLowerCase().endsWith(langFileName))
                .collect(Collectors.toList());
        for (File file : customLangFiles) {
            if (file.getName().toLowerCase().endsWith(langFileName)) {
                try (InputStream is = new FileInputStream(file)) {
                    Map<String, String> map = parseLangFile(is);
                    languageMap.putAll(map);
                    if (config.isDebugLanguage()) {
                        LOGGER.info("注入语言文件:{}", file.getAbsolutePath());
                    }
                }
            }
        }
    }

    private final Pattern a = Pattern.compile("%(\\d+\\$)?[\\d\\.]*[df]");

    private Map<String, String> parseLangFile(InputStream inputStream) {

        Map<String, String> map = new HashMap<>();
        try {
            Splitter b = Splitter.on('=').limit(2);
            BufferedSource buf = Okio.buffer(Okio.source(inputStream));
            String line;
            while ((line = buf.readUtf8Line()) != null) {
                if (!line.isEmpty() && line.charAt(0) != '#') {
                    String[] var4 = Iterables.toArray(b.split(line), String.class);
                    if (var4 != null && var4.length == 2) {
                        String var5 = var4[0];
                        String var6 = a.matcher(var4[1]).replaceAll("%$1s");
                        map.put(var5, var6);
                    }
                }
            }
        } catch (IOException e) {
            ExceptionUtils.throwException(e);
            return null;
        }
        return map;
    }
}
